// -----------------------------------------------------------------------
//  <copyright file="UpdateOrganizationCommand.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2024 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2024/12/10 14:36:07</last-date>
// -----------------------------------------------------------------------

using DaprPlus.Identity.Domain.Entities;

using DaprPlus.Identity.Application.Identity.Organizations.Specs;


namespace DaprPlus.Identity.Application.Identity.Organizations.Commands;

[AuthConfig(typeof(Organization), ResourceAccessType.RoleLimit, "Update")]
[MapTo(typeof(Organization))]
public class UpdateOrganizationCommand : IRequest<ApiResult>, ICommand
{
    public required OrganizationInDto[] Dtos { get; set; }
}

public class UpdateOrganizationCommandHandler(IRepository<Organization> repository)
    : IRequestHandler<UpdateOrganizationCommand, ApiResult>
{
    public async Task<ApiResult> Handle(UpdateOrganizationCommand request, CancellationToken cancellationToken)
    {
        foreach (var dto in request.Dtos)
        {
            var entity = await repository.FindAsync(dto.Id, cancellationToken);
            if (entity == null)
            {
                return new ApiResult(ApiResultType.Error, $"编号为 {dto.Id} 的组织机构不存在");
            }

            entity = dto.MapTo(entity);

            // 设置树路径
            if (dto.ParentId.HasValue)
            {
                var parent = await repository.FindAsync(dto.ParentId.Value, cancellationToken);
                if (parent != null)
                {
                    entity.SetTreePath(parent.TreePathString);
                }
            }
            else
            {
                entity.SetTreePath(null);
            }

            await repository.UpdateAsync(entity, cancellationToken);
        }

        return new ApiResult(ApiResultType.Success);
    }
}

public class UpdateOrganizationCommandValidator : AbstractValidator<UpdateOrganizationCommand>
{
    public UpdateOrganizationCommandValidator(IRepository<Organization> repository)
    {
        RuleFor(x => x.Dtos).NotEmpty().WithMessage("组织机构数据不能为空");
        RuleForEach(x => x.Dtos).SetValidator(new OrganizationInDtoValidator(repository));
    }
}

public class OrganizationInDtoValidator : AbstractValidator<OrganizationInDto>
{
    public OrganizationInDtoValidator(IRepository<Organization> repository)
    {
        RuleFor(x => x.Name)
            .NotEmpty().WithMessage("组织机构名称不能为空")
            .MustAsync(async (dto, name, cancellationToken) =>
            {
                var spec = new OrganizationByNameAndParentIdSpec(name, dto.ParentId, dto.Id);
                return !await repository.AnyAsync(spec, cancellationToken);
            }).WithMessage(dto => $"同级节点下已存在名称为 {dto.Name} 的组织机构");

        RuleFor(x => x.Code)
            .NotEmpty().WithMessage("组织机构代码不能为空")
            .MustAsync(async (dto, code, cancellationToken) =>
            {
                var spec = new OrganizationByCodeSpec(code, dto.Id);
                return !await repository.AnyAsync(spec, cancellationToken);
            }).WithMessage(dto => $"组织机构代码 {dto.Code} 已存在");

        RuleFor(x => x)
            .MustAsync(async (dto, cancellationToken) =>
            {
                if (!dto.ParentId.HasValue)
                {
                    return true;
                }

                var entity = await repository.FindAsync(dto.Id, cancellationToken);
                if (entity == null)
                {
                    return true;
                }

                return !entity.TreePathString.Contains($",{dto.ParentId.Value},");
            }).WithMessage("不能将组织机构移动到其子节点下");

        RuleFor(x => x.ParentId)
            .MustAsync(async (parentId, cancellationToken) =>
            {
                if (!parentId.HasValue)
                {
                    return true;
                }

                return await repository.FindAsync(parentId.Value, cancellationToken) != null;
            }).WithMessage(dto => $"上级组织机构（ID: {dto.ParentId}）不存在");
    }
}

